package org.jradweb.tools.generator.maven;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.ext.mysql.MySqlDataTypeFactory;
import org.dbunit.operation.DatabaseOperation;
import org.jradweb.tools.generator.utils.PropertiesLoader;

/**
 * Goal which touches a timestamp file.
 * 
 * @goal initData
 * @phase process-test-resources
 */
public class InitDataMojo extends AbstractMojo {

	public static final String DATABASE_DRIVER_CLASS_NAME = "database.driverClassName";

	public static final String DATABASE_URL = "database.url";

	public static final String DATABASE_USER_NAME = "database.userName";

	public static final String DATABASE_PASSWORD = "database.password";

	public static final String DATABASE_SCHEMA_NAME = "database.schemaNames";

	public static final String DATABASE_DIALECT = "database.dialect";

	/**
	 * ${project.build.directory}
	 * 
	 * @parameter expression="${project.build.directory}"
	 */
	private File buildPath;
	/**
	 * @parameter expression="${basedir}"
	 */
	private File baseDir;

	/**
	 * @parameter expression="${project.groupId}"
	 */
	private String groupId;

	/**
	 * @parameter expression="${project.artifactId}"
	 */
	private String artifactId;

	public void execute() throws MojoExecutionException, MojoFailureException {

		// check if only clean
		boolean onlyClean = false;
		String clean = System.getProperties().getProperty("onlyClean");
		if (clean != null && clean.equals("true"))
			onlyClean = true;
		getLog().info("onlyClean = " + onlyClean);

		PropertiesLoader loader = new PropertiesLoader(this.baseDir,
				this.artifactId);
		// load database connection parameters
		Properties props = null;
		try {
			props = loader.loadProjectProperties();
		} catch (FileNotFoundException e) {
			throw new MojoFailureException("load " + this.artifactId
					+ ".properties failed. message:" + e.getMessage());
		} catch (IOException e) {
			throw new MojoFailureException("load " + this.artifactId
					+ ".properties failed. message:" + e.getMessage());
		}

		IDatabaseConnection connection = null;
		try {
			Class driverClass = Class.forName(props
					.getProperty(DATABASE_DRIVER_CLASS_NAME));
			Connection jdbcConnection = DriverManager.getConnection(props
					.getProperty(DATABASE_URL), props
					.getProperty(DATABASE_USER_NAME), props
					.getProperty(DATABASE_PASSWORD));
			connection = new DatabaseConnection(jdbcConnection);
			DatabaseConfig config = connection.getConfig();
			config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY,
					new MySqlDataTypeFactory());
		} catch (ClassNotFoundException e) {
			throw new MojoFailureException(
					"get database connection failed. message:" + e.getMessage());
		} catch (SQLException e) {
			throw new MojoFailureException(
					"get database connection failed. message:" + e.getMessage());
		}

		List<MyDataSet> dataSets = this.getDataSets();

		for (int i = dataSets.size() - 1; i >= 0; i--) {
			File file = dataSets.get(i).getFile();
			IDataSet dataSet = dataSets.get(i).getDataSet();
			try {
				DatabaseOperation.DELETE_ALL.execute(connection, dataSet);
				getLog()
						.info(
								"Dataset "
										+ file.getName()
										+ " DELETE_ALL operation executed successfully.");
			} catch (DatabaseUnitException e) {
				e.printStackTrace();
				throw new MojoFailureException(
						"operator DELETE_ALL failed for dataset \""
								+ file.getName() + "\" . " + e.getMessage());
			} catch (SQLException e) {
				e.printStackTrace();
				throw new MojoFailureException(
						"operator DELETE_ALL failed for dataset \""
								+ file.getName() + "\" . message:"
								+ e.getMessage());
			}
		}

		if (!onlyClean) {
			for (int i = 0; i < dataSets.size(); i++) {
				IDataSet dataSet = dataSets.get(i).getDataSet();
				File file = dataSets.get(i).getFile();
				try {
					DatabaseOperation.INSERT.execute(connection, dataSet);
					getLog()
							.info(
									"Dataset "
											+ file.getName()
											+ " INSERT operation executed successfully.");
				} catch (DatabaseUnitException e) {
					throw new MojoFailureException(
							"operator INSERT failed for dataset \""
									+ file.getName() + "\" . message:"
									+ e.getMessage());
				} catch (SQLException e) {
					throw new MojoFailureException(
							"operator INSERT failed for dataset \""
									+ file.getName() + "\" . message:"
									+ e.getMessage());
				}
			}
		}

	}

	protected List<MyDataSet> getDataSets(File dataSetPath) throws MojoExecutionException,
			MojoFailureException {
		List<MyDataSet> dataSets = new ArrayList<MyDataSet>();

		if (!dataSetPath.exists() || !dataSetPath.isDirectory()) {
			throw new MojoFailureException(
					"DataSet path not exists,please create it: "
							+ dataSetPath.getAbsolutePath());
		}
		File[] files = this.sortAndFilterByName(dataSetPath.listFiles());
		getLog().info("Dataset files has been loaded and sorted successfully...");
		for (File file : files) {
			try {
				String fileName = file.getName();
				getLog().info("Load dataSet file " + file.getName() + "...");
				if (fileName.matches("[0-9]{1,5}_[a-z,A-Z,_]{1,100}\\.xml")) {
					IDataSet dataSet = new FlatXmlDataSet(file);
					dataSets.add(new MyDataSet(file, dataSet));
					getLog().info("DataSet loaded.");
				}
			} catch (DataSetException e) {
				String message = "Load dataset from file failed. file:"
						+ file.getAbsolutePath();
				getLog().error(message);
				throw new MojoFailureException(
						"load dataset from file failed, message:"
								+ e.getMessage());
			} catch (IOException e) {
				String message = "Load dataset from file failed. file:"
						+ file.getAbsolutePath();
				getLog().error(message);
				throw new MojoFailureException(
						"load dataset from file failed, message:"
								+ e.getMessage());
			}
		}

		return dataSets;
	}

	protected File[] sortAndFilterByName(File[] files){
		List<File> nfs=new ArrayList<File>();
		
		//filter
		for(int i=0;i<files.length;i++){
			if (!files[i].getName().matches("[0-9]{1,5}_[a-z,A-Z,_]{1,100}\\.xml")){
				files[i]=null;
			}
		}
		
		
		for(int i=0;i<files.length;i++){
			File file=null;
			int nj=0;
			for(int j=0;j<files.length;j++){
				if(less(files[j],file)){
					file=files[j];
					nj=j;
				}
			}
			files[nj]=null;
			if(file!=null){
				nfs.add(file);
			}
			else {
				break;
			}
		}	
		File na[]=new File[nfs.size()];
		nfs.toArray(na);
		return na;
	}
	private boolean less(File f1,File f2){
		if(f2==null){
			return true;
		}
		if(f1==null){
			return false;
		}
		String sf1=f1.getName();
		String sf2=f2.getName();
		
		int if1=Integer.parseInt(sf1.substring(0,4));
		int if2=Integer.parseInt(sf2.substring(0,4));
		
		return if1<if2;
		
	}
	protected List<MyDataSet> getDataSets() throws MojoExecutionException,
			MojoFailureException {

		File dataSetPath = new File(this.baseDir.getAbsolutePath()
				+ "/src/test/resources/dataset");
		if (!dataSetPath.exists() || !dataSetPath.isDirectory()) {
			throw new MojoFailureException(
					"DataSet path not exists,please create it: "
							+ dataSetPath.getAbsolutePath());
		}
		return this.getDataSets(dataSetPath);
	}

	/*
	 * load properties from ${artifactId}.properties
	 */
	private Properties loadProperties() throws FileNotFoundException,
			IOException {
		String propFile = baseDir.getAbsolutePath() + "/src/main/resources/"
				+ artifactId + ".properties";
		java.util.Properties props = new Properties();
		props.load(new FileInputStream(new File(propFile)));

		this.getLog().info(
				"database.driverClassName="
						+ props.getProperty("database.driverClassName"));
		this.getLog().info("database.url=" + props.getProperty("database.url"));
		this.getLog().info(
				"database.userName=" + props.getProperty("database.userName"));
		this.getLog().info(
				"database.password=" + props.getProperty("database.password"));
		this.getLog().info(
				"database.schemaNames="
						+ props.getProperty("database.schemaNames"));
		this.getLog().info(
				"database.dialect=" + props.getProperty("database.dialect"));
		return props;

	}

	public static void main(String[] args) throws MojoExecutionException,
			MojoFailureException {

		InitDataMojo dm = new InitDataMojo();
		File buildPath = new File("d:/workspace2/easycrm/");
		dm.baseDir = new File("d:/workspace2/easycrm/");

		dm.artifactId = "easycrm";
		dm.groupId = "com.infowarelab";

		try {
			dm.execute();
		} catch (MojoExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MojoFailureException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	class MyDataSet {
		private File file;
		private IDataSet dataSet;

		public MyDataSet(File file, IDataSet dataSet) {
			this.file = file;
			this.dataSet = dataSet;
		}

		public File getFile() {
			return file;
		}

		public void setFile(File file) {
			this.file = file;
		}

		public IDataSet getDataSet() {
			return dataSet;
		}

		public void setDataSet(IDataSet dataSet) {
			this.dataSet = dataSet;
		}
	}
}
